package com.cskaoyan.javase.oop2._1extends._9override;

/**
 *
 * 在上一节一样，父子类中的成员方法也是可以同名的。
 * 那么我们直接创建子类对象，使用子类引用接收。
 * 调用同名方法，会发现访问的结果是子类中方法的行为，那么父类中的那个同名成员方法去哪了呢？还能够访问吗？
 *
 * 首先它肯定是存在的，方法不过是方法区的二进制指令合集罢了，类加载时期，装载进方法区，不会物理消失。
 * 但 "对象名点"访问成员方法 这个语法还是和访问成员变量是有很大区别的， 我们可以写一个public方法，然后在方法中访问同名成员方法，这时会发现仍然体现出子类的行为.
 * 所以方法是"覆盖"掉了,不是"隐藏".
 * 注:
 *      但是这个覆盖不是物理意义上的覆盖,只不过是由于"对象名点"成员方法的调用机制,导致无法调用父类方法
 *      实际上用super关键字仍然可以调用该父类方法,但是super访问受访问权限限制
 *
 * 接下来重点研究"对象名点"成员方法的调用机制
 * 在研究 对象名点访问成员方法 机制时，我们主要探究两个方向：
 *      1.访问范围，究竟能够访问到哪些成员方法？根据什么来决定？
 *      2.调用结果，如果是父子类同名成员方法，那么结果是什么？根据什么来决定？
 * 对象名点访问成员方法,对象的由来，可以有三种方式：
 *      1.创建父类对象,用父类引用接收，用对象名点访问。
 *      2.创建子类对象,用子类引用接收，用对象名点访问。
 *      3.创建子类对象,用父类引用接收，用对象名点访问。
 *
 * 首先研究访问范围,访问范围仍然是一个编译概念,只和引用的数据类型有关.
 * 重点研究调用结果
 *      我们发现"对象名"点成员方法的调用结果,要根据对象的类型来确定
 *      方法调用,要体现出具体对象的行为
 *
 * 综合对象名点访问成员方法的范围和结果，发现：
 * 访问范围仍然是要靠 引用的数据类型 来决定。
 * 但是方法的调用结果，就需要考虑对象的具体类型，是何种对象，就体现出它的行为。
 *
 *
 * 注意事项：
 *      1.父子类中一旦存在父子类同名的成员方法，那么只要创建子类对象，在任何位置都无法再直接访问到父类成员方法了，这就是继承中的方法的覆盖。
 *      2.当然，方法的覆盖不是物理意义上的覆盖，只是方法的访问机制决定的。这个父类中的同名方法，仍然可以使用super关键字去访问到，当然前提是有访问权限。
 *      3.方法的调用之所以体现为覆盖，这是因为方法的调用结果是根据对象的实际类型决定的，和引用没有任何关系。
 *
 *
 *
 * @since 09:51
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        s.test();
        s.invokeFatherTest();
        s.superInvokeFatherTest();*/
        // 1.创建父类对象,用父类引用接收，用对象名点访问。
        Father f = new Father();
        f.test();
        // 2.创建子类对象,用子类引用接收，用对象名点访问。
        Son s = new Son();
        // s.testFather();
        s.test();
        // 3.创建子类对象,用父类引用接收，用对象名点访问。
        Father fs = new Son();
        fs.test();
        // fs.testFather();
        // fs.testSon();
    }
}

class Father {
    public void test() {
        System.out.println("father");
    }

    public void testFather() {
        System.out.println("only father");
    }

    // 提供一个test方法的"getter"方法
    public void invokeFatherTest(){
        test();
    }
}

class Son extends Father {
    public void test() {
        System.out.println("son");
    }

    public void testSon() {
        System.out.println("only son");
    }
    // public void superInvokeFatherTest(){
    //     super.test();
    // }
}
